use proc_macro::{TokenStream};
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{parse_macro_input, Attribute, Error, Expr, ItemTrait, Lit, LitInt, LitStr, Meta, Token, TraitItem};
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use crate::parse::parse_param;
use crate::util::to_upper_name;

pub fn do_rpc_service(attr: TokenStream, item: TokenStream) -> TokenStream {
    // 将输入解析为trait定义
    let input = parse_macro_input!(item as ItemTrait);
    let service_info = parse_macro_input!(attr as RpcServiceInfo);

    let trait_name = &input.ident;
    let methods = &input.items;

    // 为每个方法生成一个默认实现（panic）
    let method_impls = methods.iter().map(|item| {
        if let TraitItem::Fn(method) = item {
            let sig = &method.sig;
            let ident = &sig.ident;
            let attrs = &method.attrs;
            let input = &sig.inputs;
            let param = parse_param(&sig);
            let params = param.params;
            let ref_params = param.ref_params;
            let output = &sig.output;

            // let (path, timeout) = (None, None); //parse_router2(&attrs);
            // let path = path.unwrap_or_else(|| "/hello".to_string());
            // let timeout = timeout.unwrap_or_else(||50);
            let path = get_path(&attrs);
            let timeout: u32 = service_info.timeout;

            let bytes = if ref_params.len() > 1 {
                quote! {
                    rpc::encode(&self.context, &(#(#params),*))?
                }
            } else {
                quote! {
                    rpc::encode(&self.context, #(#ref_params),*)?
                }
            };
            // 保留方法签名，但将方法体替换为unimplemented
            quote! {
                async fn #ident(#input) #output {
                    let bytes = #bytes;
                    let local_seq = self.context.get_local_seq_creator().create_seq();
                    let header = rpc::dto::RpcHeader::new(#path, local_seq.clone(), 0);
                    let rpc_data = rpc::dto::RpcData::build(header, bytes);
                    let result = rpc::encode_rpc_data(&self.context, &rpc_data)?;

                    let data = channel.write(local_seq, result, #timeout).await?;
                    let value = rpc::decode(&self.context, data)?;
                    Ok(value)
                }
            }
        } else {
            // 如果不是方法，我们就不生成任何代码，但需要返回一个空的TokenStream
            quote! {}
        }
    });

    // 生成一个结构体，结构体名称为TraitNameImpl
    let impl_struct_name = syn::Ident::new(&format!("{}Impl", trait_name), trait_name.span());

    // 为这个结构体生成一个空的trait实现
    let expanded = quote! {
        #input

        pub struct #impl_struct_name {
            context: rpc::RpcContext,
        }

        impl #impl_struct_name {

            pub fn new(context: rpc::RpcContext) -> #impl_struct_name {
                #impl_struct_name {
                    context,
                }
            }
        }

        #[async_trait::async_trait]
        impl #trait_name for #impl_struct_name {
            #(#method_impls)*
        }
    };

    proc_macro::TokenStream::from(expanded)
}

pub fn do_service(input: TokenStream) -> TokenStream {
    let input : MacroInput = parse_macro_input!(input as MacroInput);

    let function_name_to_upper_name = to_upper_name(&input.service.to_string());

    let router_factory_name = format!("{}Impl", function_name_to_upper_name);
    let router_factory = Ident::new(&router_factory_name, Span::call_site());

    let context = input.context;
    let expanded = quote! {
        #router_factory::new(#context)
    };
    TokenStream::from(expanded)
}


struct MacroInput {
    context: Expr,
    service: Ident,
}

impl Parse for MacroInput {
    fn parse(input: ParseStream) -> Result<Self, Error> {
        let value = input.parse()?;  // 解析要转换的值
        input.parse::<syn::Token![,]>()?;  // 解析逗号分隔符
        let target_type = input.parse()?;  // 解析目标类型
        Ok(MacroInput {
            context: value,
            service: target_type,
        })
    }
}

fn get_path(attrs: &Vec<Attribute>) -> Option<String> {
    for attr in attrs {
        if let Meta::NameValue(nv) = &attr.meta {
            if nv.path.is_ident("path") {
                let value = &nv.value;
                if let Expr::Lit(nv) = value {
                    if let Lit::Str(lit_str) = &nv.lit {
                        return Some(lit_str.value());
                    }
                }
            }
        }
    }
    None
}

fn parse_router2(attrs: &Vec<Attribute>) -> (Option<String>, Option<u32>) {
    let mut path = None;
    let mut timeout = None;

    for attr in attrs {
        if attr.path().is_ident("rpc_path") {
            attr.parse_nested_meta(|meta| {
                if meta.path.is_ident("name") {
                    let lit: LitStr = meta.input.parse().unwrap();
                    path = Some(lit.value());
                } else if meta.path.is_ident("timeout") {
                    let lit: LitInt = meta.input.parse().unwrap();
                    timeout = Some(lit.base10_parse::<u32>().unwrap());
                }
                Ok(())
            }).unwrap();
        }
    }
    (path, timeout)
}

fn parse_router(attrs: &Vec<Attribute>) -> (Option<String>, Option<u32>) {
    let mut path = None;
    let mut timeout = None;

    for attr in attrs {
        if attr.path().is_ident("router") {
            let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated).unwrap();
            for meta in nested {
                if let Meta::NameValue(nv) = &meta {
                    if meta.path().is_ident("path") {
                        let value = &nv.value;
                        if let Expr::Lit(nv) = value {
                            if let Lit::Str(lit_str) = &nv.lit {
                                path = Some(lit_str.value());
                            }
                        }
                    } else if meta.path().is_ident("timeout") {
                        let value = &nv.value;
                        if let Expr::Lit(nv) = value {
                            if let Lit::Int(int) = &nv.lit {
                                timeout = Some(int.base10_parse::<u32>().unwrap());
                            }
                        }
                    }
                }
            }
        }
    }
    (path, timeout)
}


struct RpcServiceInfo {
    timeout: u32,
}

impl Parse for RpcServiceInfo {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let metas = Punctuated::<Meta, Token![,]>::parse_terminated(input)?;

        let mut timeout: u32 = 60;
        for meta in metas {
            if let Meta::NameValue(name_value) = meta {
                if name_value.path.is_ident("timeout") {
                    if let Expr::Lit(nv) = name_value.value {
                        if let Lit::Int(lit) = &nv.lit {
                            timeout = lit.base10_parse::<u32>().unwrap();
                        }
                    }
                }
            }
        }
        Ok(RpcServiceInfo { timeout })
    }
}